import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
import org.apache.calcite.prepare.CalciteCatalogReader;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.impl.ScalarFunctionImpl;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.tools.Planner;

public class TestCustomFunction {
    private static final String SQL      = "select SQUARE_FUNC(1)";
    private static final String FUN_NAME = "SQUARE_FUNC";

    public static void main(String[] args) throws Exception {
        useFramworksExec();
    }

    private static void useFramworksExec() throws Exception {
/*        CalciteSchema rootSchema = CalciteSchema.createRootSchema(false, false);
        SchemaPlus schema = rootSchema.plus();
        schema.add(FUN_NAME, ScalarFunctionImpl.create(SquareFunction.class, "eval"));
        CalciteCatalogReader reader = new CalciteCatalogReader(rootSchema,
                SqlParser.Config.DEFAULT.caseSensitive(),
                rootSchema.path(null),
                new JavaTypeFactoryImpl());



        FrameworkConfig config = Frameworks.newConfigBuilder().operatorTable(reader).defaultSchema(schema).build();
        Planner planner = Frameworks.getPlanner(config);
        SqlNode ast = planner.parse(SQL);
        SqlNode validatedAst = planner.validate(ast);
        System.out.println(validatedAst.toString());*/
    }

    /**
     * As CalciteCatalogReader object requires context, There is another way to register custom Functions.
     *
     * SqlFunction countRelation = new SqlFunction("COUNT_RELATION",
     *                 SqlKind.OTHER_FUNCTION,
     *                 ReturnTypes.INTEGER,
     *                 null,
     *                 OperandTypes.STRING,
     *                 SqlFunctionCategory.NUMERIC);
     *
     *         SqlStdOperatorTable sqlStdOperatorTable = SqlStdOperatorTable.instance();
     *         sqlStdOperatorTable.register(countRelation);
     *
     *         this.frameworkConfig = Frameworks.newConfigBuilder()
     *                 .parserConfig(parserConfig)
     *                 .defaultSchema(schemaPlus)
     *                 .programs(Programs.sequence(Programs.ofRules(Programs.RULE_SET), Programs.CALC_PROGRAM))
     *                 .traitDefs(traitDefs)
     *                 .operatorTable(sqlStdOperatorTable)
     *                 .build();
     */

    public class SquareFunction  {
        public int eval(int a) {
            return a*a;
        }
    }
}
